﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameController : MonoBehaviour, IUserAction, IPSActionCallback {
    IActionManager actionManager;
    DiskFactory diskFactory;
    Material[] materials;
    Hashtable obj2points;
    Hashtable obj2actions;
    Ruler ruler;
    float sumWeight;
    public int numRound;
    public int trialPerRound;
    
    int score;
    int round;
    int numHitOrMiss;
    GameState gamestate;
    float currentScale;

    void Awake() {
        materials = new Material[4];
        for (int i = 0; i < 4; ++i) {
            materials[i] = Resources.Load<Material>("Materials/Material" + i);
            if (materials[i] == null) {
                Debug.LogError("materials[" + i + "] is null");
            }
        }
        obj2points = new Hashtable();
        obj2actions = new Hashtable();
        ruler = Resources.Load<Ruler>("GameRuler");
        if (ruler == null) {
            Debug.LogError("ruler is null");
        }
        if (ruler.probabilityWeight.Length != 4) {
            Debug.LogError("ruler.probabilityWeight.Length != 4");
        }
        if (ruler.speed.Length != 4) {
            Debug.LogError("ruler.speed.Length != 4");
        }
        if (ruler.point.Length != 4) {
            Debug.LogError("ruler.point.Length != 4");
        }
        sumWeight = 0.0f;
        for (int i = 0; i < 4; ++i) {
            sumWeight += ruler.probabilityWeight[i];
        }
    }

    void Start() {
        actionManager = Singleton<PSActionManager>.Instance;
        if (actionManager == null) {
            Debug.LogError("actionManager is null");
        }
        diskFactory = Singleton<DiskFactory>.Instance;
        if (diskFactory == null) {
            Debug.LogError("diskFactory is null");
        }
        
        Init();
    }

    void Update() {
        
    }

    void NextRound() {
        gamestate = GameState.READY;
        ++round;
        PSHaltAction[] haltActions = new PSHaltAction[trialPerRound + 1];
        for (int i = 0; i <= trialPerRound; ++i) {
            haltActions[i] = PSHaltAction.GetPSAction();
            float delay = (i == 0? 1.5f: Random.Range(0.5f, 2.0f));
            int id = (i == 0? 3000: 1000);
            haltActions[i].Init(delay, id, this);
        }
        PSSequenceAction sequenceAction = PSSequenceAction.GetPSAction();
        sequenceAction.Init(haltActions);
        actionManager.RunAction(sequenceAction);
        numHitOrMiss = 0;
    }

    /* 动作回调 */
    public void PSActionEvent(PSAction source, PSActionEventType events, int identifier, Object param) {
        if (events != PSActionEventType.COMPLETE) {
            return;
        }
        if (identifier == 1000) {
            /* 决定飞碟的起点和终点 */
            Vector3 start, end;
            int side = Random.Range(0, 3);
            switch (side) {
                case 0:
                case 1:
                    start = new Vector3(14.0f * (side == 0? -1: 1), Random.Range(-3.0f, 1.0f), 0.0f);
                    break;
                default:
                    start = new Vector3(Random.Range(-9.0f, 9.0f), -6.0f, 0.0f);
                    break;
            }
            end = new Vector3(Random.Range(-9.0f, 9.0f), 7.7f, 0.0f);

            /* 决定飞碟的速度、颜色、得分 */
            GameObject disk = diskFactory.GetDisk();
            disk.transform.position = start;
            disk.transform.localScale = currentScale * new Vector3(1, 1, 1);
            float sm = 0.0f;
            float rand = Random.Range(0.0f, sumWeight);
            for (int i = 0; i < 4; ++i) {
                sm += ruler.probabilityWeight[i];
                if (sm > rand) {
                    PSMoveToAction action = PSMoveToAction.GetPSAction();
                    action.Init(end, ruler.speed[i], disk, 2000, this);
                    actionManager.RunAction(action);
                    disk.GetComponent<MeshRenderer>().material = materials[i];
                    obj2points[disk] = ruler.point[i];
                    obj2actions[disk] = action;
                    break;
                }
            }

        }
        else if (identifier == 2000) {
            DestroyDiskInEitherWay((GameObject)param);
        }
        else if (identifier == 3000) {
            gamestate = GameState.INGAME;
        }
    }

    void DestroyDiskInEitherWay(GameObject obj) {
        ++numHitOrMiss;
        diskFactory.FreeDisk(obj);
        if (numHitOrMiss >= trialPerRound) {
            if (round == numRound) {
                gamestate = GameState.OVER;
            }
            else {
                currentScale *= 0.85f;
                NextRound();
            }
        }
    }

    /* 以下是IUserAction的具体实现 */
    public GameState GetGameState() {
        return gamestate;
    }
    public int GetScore() {
        return score;
    }
    public int GetRound() {
        return round;
    }
    public void Init() {
        round = 0;
        score = 0;
        numHitOrMiss = 0;
        gamestate = GameState.READY;
        currentScale = ruler.baseScale;
        NextRound();
    }
    public void HitDisk(GameObject obj) {
        score += (int)obj2points[obj];
        ((PSAction)obj2actions[obj]).SetOver(true);
        DestroyDiskInEitherWay(obj);
    }
}
